<template>
<div>
    <h4>自定义指令</h4>
        <hr>
        <h5>对象形式写法</h5>
        <div class="pre">
            <button @click="show=!show">change</button>
             <div v-move-directive v-if="show" @click="change">我是绑定自定义指令对象的目标元素{{content.value}}</div>
        </div>
        <hr>
        <h5>函数形式写法</h5>
        <div class="pre">
            <button @click="show2=!show2">change</button>
             <div v-move-fn="{background: value}" v-if="show2" @click="change2">我是绑定自定义指令对象的目标元素{{content2.value}}</div>
        </div>
        <h5>实现一个拖拽的自定义指令</h5>
        <div class="drag-wrap">
            <div class="diag-box" v-move>
                <header>title</header>
                <article>content</article>
            </div>
        </div>



        <div v-move class="box">
            <div class="header"></div>
            <div class="content">
            内容
            </div>
        </div>
</div>
</template>
    
<script setup lang='ts'>

import { Directive, getCurrentInstance } from "@vue/runtime-core";
import { ComponentInternalInstance, ref } from "vue";

// 获取全局变量
const { appContext } = <ComponentInternalInstance>getCurrentInstance();
console.log('--------全局变量：', appContext.config.globalProperties.env);


    // 在setup内定义局部指令，但这里有一个需要注意的限制：
    //必须以 vNameOfDirective 的形式来命名本地自定义指令，以使得它们可以直接在模板中使用
    // Vue2 指令 bind inserted update componentUpdated unbind
    const vMoveDirective: Directive = {
        created(...ags: any[]) {
            // 元素初始化的时候
            console.log('directive created=>', ags);
        },
        beforeMount(...ags: any[]){
            // 指令绑定到元素后调用 只调用一次
            console.log('beforeMount created=>', ags);
        },
        mounted(...ags: any[]) {
            // 元素插入父级dom调用
            console.log('mounted created=>', ags);
        },
        beforeUpdate(...ags: any[]) {
            // 元素被更新之前调用
            console.log('beforeUpdate created=>', ags);
        },
        updated(...ags: any[]) {
            //  这个周期方法被移除 改用updated
            console.log('updated created=>', ags);

        },
        beforeUnmount(...ags: any[]) {
            //  在元素被移除前调用
            console.log('beforeUnmount created=>', ags);
        },
        unmounted(...ags: any[]) {
            // 指令被移除后调用 只调用一次
            console.log('unmounted created=>', ags);
        }
    };

// 一个 el  当前绑定的DOM 元素

// 第二个 binding
    // instance：使用指令的组件实例。
    // value：传递给指令的值。例如，在 v-my-directive="1 + 1" 中，该值为 2。
    // oldValue：先前的值，仅在 beforeUpdate 和 updated 中可用。无论值是否有更改都可用。
    // arg：传递给指令的参数(如果有的话)。例如在 v-my-directive:foo 中，arg 为 "foo"。
    // modifiers：包含修饰符(如果有的话) 的对象。例如在 v-my-directive.foo.bar 中，修饰符对象为 {foo: true，bar: true}。
    // dir：一个对象，在注册指令时作为参数传递。例如，在以下指令中
// 第三个 当前元素的虚拟DOM 也就是Vnode

// 第四个 prevNode 上一个虚拟节点，仅在 beforeUpdate 和 updated 钩子中可用 

let show = ref<boolean>(true);
let content = ref({
    value: 'dog'
});
let change = function() {
    content.value.value+= "!";
}



// 函数形式写法
let show2 = ref<boolean>(true);
let content2 = ref({
    value: 'dog'
});
let change2 = function() {
    content2.value.value+= "!";
};
let value = ref('red');

const vMoveFn: Directive = (...ags:any[]) => {
    console.log('函数形式指令vMoveFn：', ags);
    ags[0].style.backgroundColor = ags[1].value.background;
};



// 拖拽功能自定义指令
const vMove: Directive = {
    mounted(el: HTMLHtmlElement) {
        console.log('拖拽自定义指令：', el);
        let mousedown = (e: MouseEvent) => {
            let startX = e.clientX;
            let startY = e.clientY;
            console.log('mousedown', startX, startY,  el.offsetLeft, el.offsetTop);
            let moseMove = function(e: MouseEvent) {
                el.style.left = e.clientX - startX + el.offsetLeft + 'px';
                el.style.top = e.clientY - startY + el.offsetTop + 'px';
                startX = e.clientX;
                startY = e.clientY;
                console.log('mousemove', e.clientX, e.clientY);
            };
            document.body.addEventListener('mousemove', moseMove);
            document.body.addEventListener('mouseup', () => {
                document.body.removeEventListener('mousemove', moseMove);
            })
        };
        el.addEventListener('mousedown', mousedown);
    }
};

// const vMove: Directive = {
//   mounted(el: HTMLElement) {
//     let moveEl = el.firstElementChild as HTMLElement;
//     const mouseDown = (e: MouseEvent) => {
//       //鼠标点击物体那一刻相对于物体左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
//       console.log(e.clientX, e.clientY, "-----起始", el.offsetLeft);
//       let X = e.clientX - el.offsetLeft;
//       let Y = e.clientY - el.offsetTop;
//       const move = (e: MouseEvent) => {
//         el.style.left = e.clientX - X + "px";
//         el.style.top = e.clientY - Y + "px";
//         console.log(e.clientX, e.clientY, "---改变");
//       };
//       document.addEventListener("mousemove", move);
//       document.addEventListener("mouseup", () => {
//         document.removeEventListener("mousemove", move);
//       });
//     };
//     moveEl.addEventListener("mousedown", mouseDown);
//   },
// };
</script>
    
<style lang="less">
    .drag-wrap {
        width: 100%;
        height: 600px;
        background: #999;
        position: relative;
    }
    .diag-box {
        width: 300px;
        height: 260px;
        background-color: red;
        border-radius: 10px;
        position: absolute;
        top: 10px;
        left: 30px;
        cursor: move;
    }



.box {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 200px;
  height: 200px;
  border: 1px solid #ccc;
  .header {
    height: 20px;
    background: black;
    cursor: move;
  }
  .content {
      height: 100%;
      background-color: #999;
  }
  }
</style>